﻿using Etapa1.Objects;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using PloobsEngine;
using PloobsEngine.Cameras;
using PloobsEngine.Entity;
using PloobsEngine.Input;
using PloobsEngine.Light;
using PloobsEngine.Material;
using PloobsEngine.Modelo;
using PloobsEngine.Physics;
using PloobsEngine.Physics.Bepu;
using PloobsEngine.SceneControl;
using PloobsEngine.Trigger;
using PloobsEngineDemo3;
using PloobsEngine.Draw;
using PloobsEngine.MessageSystem;

namespace Etapa1.Screens
{   
    /// <summary>
    /// Trigger Screen
    /// Jogue bolas no cilo ;)
    /// </summary>
    public class TriggerBepuScreen : SceneScreen
    {
        private BepuPhysicWorld physicWorld;
        private BrutalForceWorld mundo;
        private EngineStuff engine;        
        ICamera cam;

        public TriggerBepuScreen(EngineStuff es)
        {
            this.engine = es;
            physicWorld = new BepuPhysicWorld();
            mundo = new BrutalForceWorld(physicWorld);                                    
        }
        
        public override void LoadContent(EngineStuff es)
        {
            ///Adicionando Componente de Mensagens 
            ///Utilizado pelo Trigger
            MessageDeliver md = new MessageDeliver();
            engine.AddComponent(md);

            ///Adicionando Componente de Input 
            ///Utilizado pelo "Atirador de bolas"
            InputAdvanced inp = new InputAdvanced(es);
            engine.AddComponent(inp);

            base.LoadContent(es);

            #region Trigger
            ///Criacao de um Trigger
            {
                ///Modelo cujo formato sera utilizado para disparar o trigger
                SimpleModel sm = new SimpleModel("..\\Content\\Model\\cilos", "..\\Content\\Textures\\white");
                sm.LoadModelo();
                ///Criacao do Triangle Mesh
                TriangleMeshObject tm = new TriangleMeshObject(new Vector3(200, 5, 0), sm);
                ///Criacao do Evento q sera disparado qd o trigger for acionado
                ///Pode-se criar outros tipos de eventos, basta extender a classe  IEvent<ITrigger>
                ///O parametro passado eh o canal em que o trigger enviara suas mensagens
                ///Qualquer Entidade que extende IRecieveMessageEntity pode receber mensagens
                TriggerEvent te = new TriggerEvent("TriggerEvent","TriggerTest1");
                ///Criacao do Trigger
                BepuTrigger bt = new BepuTrigger(tm, te, true, true, true, true);
                ///Adiciona o trigger ao mundo
                mundo.AddTrigger(bt);

                ///Adicona um objeto na posicao do trigger (Objeto FANTASMA, nao sera detectado pelo trigger)
                ///Facilita na localizacao do Trigger (cilos brancos)
                GhostObject ghost = new GhostObject(new Vector3(200, 5, 0), Matrix.Identity,Vector3.One);
                CustomDeferred shader = new CustomDeferred(false, false, false, false);
                shader.Initialize();
                IMaterial mat = new Material(shader);
                IObject obj3 = new SimpleObject(mat, ghost, sm);
                mundo.AddObject(obj3);      

            }


            #endregion

            ///Criacao de um Objeto q recebera mensagens do trigger
            #region Models
            {
                SimpleModel sm = new SimpleModel("..\\Content\\Model\\cubo", "..\\Content\\Textures\\white");
                sm.LoadModelo();
                IPhysicObject pi = new TriangleMeshObject( sm,new Vector3(20,50,50), Matrix.Identity,Vector3.One * 10);
                NormalDeferred shader = new NormalDeferred();                
                shader.Initialize();
                IMaterial mat = new Material(shader);
                SimpleObject obj3 = new SimpleObject(mat, pi, sm);
                ///Cadastra uma funcao para tratar das mensagens recebidas
                ///existem outras maneiras de fazer isso, como Extender a classe IObject e sobrescrever o metodo HandleMessage
                obj3.OnRecieveMessage += new OnRecieveMessage(obj3_OnRecieveMessage);
                mundo.AddObject(obj3);
                ///Adiciona o Objeto criado ao grupo "TriggerEvent" que recebera as mensagens do trigger
                EntityMapper.getInstance().AddgrouptagRecieveEntity("TriggerEvent", obj3);
            }


            ///Cenario de sempre
            {
                SimpleModel sm = new SimpleModel("..\\Content\\Model\\cenario");
                sm.LoadModelo();
                IPhysicObject pi = new TriangleMeshObject(Vector3.Zero, sm);                
                CustomDeferred shader = new CustomDeferred(false, false, false, false);
                shader.SpecularIntensity = 0;
                shader.SpecularPower = 0;
                shader.Initialize();
                IMaterial mat = new Material(shader);
                IObject obj3 = new SimpleObject(mat, pi, sm);
                mundo.AddObject(obj3);
            }
            

            #endregion        
    
            ///Demonstracao de que qualquer entidade pode receber mensagens
            ///Olhar a implementacao desta classe, esta no fim deste arquivo
            ReciveMessage rmessage = new ReciveMessage();


            cam = new CameraFirstPerson(true);            
            cam.FarPlane = 2000;

            LightThrowBepu lt = new LightThrowBepu(mundo, engine);         

            #region NormalLight
            DirectionalLight ld1 = new DirectionalLight(Vector3.Left, Color.White);
            DirectionalLight ld2 = new DirectionalLight(Vector3.Right, Color.White);
            DirectionalLight ld3 = new DirectionalLight(Vector3.Backward, Color.White);
            DirectionalLight ld4 = new DirectionalLight(Vector3.Forward, Color.White);
            DirectionalLight ld5 = new DirectionalLight(Vector3.Down, Color.White);
            float li = 0.4f;
            ld1.LightIntensity = li;
            ld2.LightIntensity = li;
            ld3.LightIntensity = li;
            ld4.LightIntensity = li;
            ld5.LightIntensity = li;
            mundo.AddLight(ld1);
            mundo.AddLight(ld2);
            mundo.AddLight(ld3);
            mundo.AddLight(ld4);
            mundo.AddLight(ld5);
            #endregion

            ////Criacao de uma Tecnica
            DeferredRenderTechnic dr = new DeferredRenderTechnic(engine);
            
            IRenderTechnic[] rt = new IRenderTechnic[] { dr };
            this.RenderTechnics = rt;
            mundo.AddCamera(cam);
            this.World = mundo;

            ///Buffer de desenho 2D e texto nao sera limpo automaticamente a todo frame
            Drawing.setClearEveryFrame(false);

        }

        /// <summary>
        /// Chamado qd uma mensagem chega
        /// </summary>
        /// <param name="Reciever"></param>
        /// <param name="mes"></param>
        void obj3_OnRecieveMessage(IObject Reciever, PloobsEngine.MessageSystem.Message mes)
        {
            ///Checa se eh a mensagem correta
            if (mes.SenderType == PloobsEngine.MessageSystem.SenderType.EVENT && mes.Tag == "TriggerEvent")
            {
                ///Limpa Buffer de desenho 2D e texto 
                Drawing.ClearAll();
                BepuTrigger trigger = (BepuTrigger)mes.Content;                
                ///Escreve Texto na tela
                Drawing.Draw2dTextAt2dLocation("Objeto: Trigger acionado " + mes.Cod + " Objeto " + trigger.ContactEntity.Name, new Vector2(20, 20), Color.White);
            }
        }


    }


    public class ReciveMessage : IRecieveMessageEntity
    {

        public ReciveMessage()
        {
            ///Registra esta entidade
            EntityMapper.getInstance().AddEntity(this);
            ///Insere esta entidade em um canal (passara a receber mensagens deste canal)
            ///PARA ADICIONAR UMA ENTIDADE EM UM CANAL DEVE-SE ANTES REGISTRAR A ENTIDADE
            EntityMapper.getInstance().AddgrouptagRecieveEntity("TriggerEvent",this);
        }
        ~ReciveMessage()
        {
            ///DESREGISTRAR QD ENTIDADE DEIXA DE EXISTIR
            ///este metodo remove a entidade de todos os canais
            EntityMapper.getInstance().RemoveEntity(this);            
        }

        #region IRecieveMessageEntity Members

        public bool HandleThisMessageType(SenderType type)
        {
            return true;
        }

        public void HandleMessage(Message mes)
        {
            if (mes.SenderType == PloobsEngine.MessageSystem.SenderType.EVENT && mes.Tag == "TriggerEvent")
            {
                BepuTrigger trigger = (BepuTrigger)mes.Content;
                Drawing.Draw2dTextAt2dLocation("ReciveMessage: Trigger acionado " + mes.Cod + " Objeto " + trigger.ContactEntity.Name, new Vector2(20, 40), Color.White);
            }
        }

        #endregion

        #region IEntity Members
        int id;
        public int getId()
        {
            return id;
        }

        public void setId(int id)
        {
            this.id = id;
        }

        #endregion
    }

}

